package plus.easydo.xxl.job.request;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import plus.easydo.xxl.job.config.XxlJobPlusProperties;
import plus.easydo.xxl.job.model.ExecutorInfo;
import plus.easydo.xxl.job.model.SchedulerInfo;
import plus.easydo.xxl.job.model.TriggerScheduler;
import plus.easydo.xxl.job.model.XxlJobResult;
import plus.easydo.xxl.job.exception.XxlJobPlusException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.net.HttpCookie;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static plus.easydo.xxl.job.config.XxlJobPlusConstants.*;

/**
 * @author yuzhanfeng
 * @Date 2023/2/16 16:18
 * @Description huTool实际请求对象
 */
@Component("hutool")
public class HuToolXxlJobRequest implements XxlJobRequest{

    Logger log = LoggerFactory.getLogger(HuToolXxlJobRequest.class);

    @Autowired
    private XxlJobPlusProperties xxlJobPlusProperties;

    @Override
    public String login() {
        return login(xxlJobPlusProperties.getAdmin().getAddresses(),
                xxlJobPlusProperties.getAdmin().getUsername(), xxlJobPlusProperties.getAdmin().getPassword());
    }

    /**
     * 登录获得token
     *
     * @param address address
     * @param username username
     * @param password password
     * @return java.lang.String
     * @author laoyu
     * @date 2023/2/16
     */
    @Override
    public String login(String address, String username, String password) {
        try {
            HttpResponse response = HttpRequest.post(address + LOGIN + "?" + "userName=" + username + "&password=" + password).execute();
            JSONObject loginResponseBody = JSONUtil.parseObj(response.body());
            Integer code = loginResponseBody.getInt("code");
            // 校验返回结果是否正确
            Assert.isTrue(code == HttpStatus.HTTP_OK, loginResponseBody.getStr("msg"));
            // 获取用户cookie信息
            List<HttpCookie> cookies = response.getCookies();
            log.debug("cookies:{}", cookies);
            assert null != cookies && !cookies.isEmpty();
            return cookies.get(0).getValue();
        } catch (Exception e) {
            log.warn("xxl-job登录异常,{}", e.getMessage());
            throw new XxlJobPlusException("xxl-job登录异常:" + e.getMessage());
        }
    }

    /**
     * 获取执行器列表
     *
     * @return java.util.List<com.yunli.govaffair.xxl.job.model.ExecutorInfo>
     * @author laoyu
     * @date 2023/2/17
     */
    @Override
    public List<ExecutorInfo> executorList() {
        return executorList(login(), xxlJobPlusProperties.getAdmin().getAddresses(), xxlJobPlusProperties.getExecutor().getAppname());
    }


    /***
     * 获取执行器列表
     *
     * @param cookie cookie
     * @param address address
     * @param appname appname
     * @return java.util.List<com.yunli.govaffair.xxl.job.model.ExecutorInfo>
     * @author laoyu
     * @date 2023/2/16
     */
    @Override
    public List<ExecutorInfo> executorList(String cookie, String address, String appname) {
        try {
            JSONObject params = JSONUtil.createObj();
            if (CharSequenceUtil.isNotBlank(appname)) {
                params.append("appname", appname);
            }
            HashMap<String,String> httpHeaders = MapUtil.newHashMap(1);
            httpHeaders.put(COOKIE, cookie);
            return this.list(address + EXECUTOR_REGISTER_PATH, httpHeaders, params, ExecutorInfo.class);
        } catch (Exception e) {
            log.warn("xxl-job执行器列表查询异常,{}", e.getMessage());
            throw new XxlJobPlusException("xxl-job执行器列表查询异常:" + e.getMessage());
        }
    }

    @Override
    public String executorRegister() {
        String appName = xxlJobPlusProperties.getExecutor().getAppname();
        String title = xxlJobPlusProperties.getExecutor().getTitle();
        ExecutorInfo executorInfo = new ExecutorInfo();
        executorInfo.setAppname(appName);
        executorInfo.setTitle(title);
        executorInfo.setAddressType(0);
        return executorRegister(login(),xxlJobPlusProperties.getAdmin().getAddresses(), executorInfo);
    }

    /**
     * 注册执行器
     *
     * @param cookie cookie
     * @param address address
     * @param executorInfo executorInfo
     * @author laoyu
     * @date 2023/2/16
     */
    @Override
    public String executorRegister(String cookie, String address, ExecutorInfo executorInfo) {
        try {
            HashMap<String, String> headers = MapUtil.newHashMap(1);
            headers.put(COOKIE, cookie);
            JSONObject params = JSONUtil.createObj();
            params.append("appname", executorInfo.getAppname());
            params.append("title", executorInfo.getTitle());
            params.append("addressType", executorInfo.getAddressType());
            XxlJobResult result = requestAndResponseCheck(address + EXECUTOR_LIST_PATH, headers, params);
            return result.getContent();
        } catch (Exception e) {
            log.warn("xxl-job执行器注册异常,{}", e.getMessage());
            throw new XxlJobPlusException("执行器注册异常:" + e.getMessage());
        }
    }

    @Override
    public List<SchedulerInfo> schedulerList(Integer jobGroup) {
        return schedulerList(login(),xxlJobPlusProperties.getAdmin().getAddresses(),jobGroup);
    }


    /**
     * 调度任务列表
     *
     * @param cookie cookie
     * @param address address
     * @param jobGroup jobGroup
     * @return java.util.List<com.yunli.govaffair.xxl.job.model.SchedulerInfo>
     * @author laoyu
     * @date 2023/2/16
     */
    @Override
    public List<SchedulerInfo> schedulerList(String cookie, String address, Integer jobGroup) {
        try {
            JSONObject params = JSONUtil.createObj();
            if (!Objects.isNull(jobGroup)) {
                params.append("jobGroup", jobGroup);
            }
            params.append("triggerStatus", -1);
            HashMap<String, String> httpHeaders = MapUtil.newHashMap(1);
            httpHeaders.put(COOKIE, cookie);
            return this.list(address + SCHEDULER_LIST_PATH, httpHeaders, params, SchedulerInfo.class);
        } catch (Exception e) {
            log.warn("xxl-job调度任务列表获取异常,{}", e.getMessage());
            throw new XxlJobPlusException("调度任务列表获取异常:" + e.getMessage());
        }
    }

    @Override
    public String schedulerRegister(SchedulerInfo schedulerInfo) {
        return schedulerRegister(login(),xxlJobPlusProperties.getAdmin().getAddresses(),schedulerInfo);
    }

    /**
     * 注册调度任务
     *
     * @param cookie cookie
     * @param address address
     * @param schedulerInfo schedulerInfo
     * @author laoyu
     * @date 2023/2/16
     */
    @Override
    public String schedulerRegister(String cookie, String address, SchedulerInfo schedulerInfo) {
        try {
            HashMap<String, String> httpHeaders = MapUtil.newHashMap(1);
            httpHeaders.put(COOKIE, cookie);
            JSONObject params = schedulerInfoToJson(schedulerInfo);
            XxlJobResult result = requestAndResponseCheck(address + SCHEDULER_REGISTER_PATH, httpHeaders, params);
            return result.getContent();
        } catch (Exception e) {
            log.warn("xxl-job调度任务注册异常,{}", e.getMessage());
            throw new XxlJobPlusException("调度任务注册异常:" + e.getMessage());
        }
    }

    @Override
    public void schedulerUpdate(SchedulerInfo schedulerInfo) {
        schedulerUpdate(login(),xxlJobPlusProperties.getAdmin().getAddresses(),schedulerInfo);
    }

    /**
     * 注册调度任务
     *
     * @param cookie cookie
     * @param address address
     * @param schedulerInfo schedulerInfo
     * @author laoyu
     * @date 2023/2/16
     */
    @Override
    public void schedulerUpdate(String cookie, String address, SchedulerInfo schedulerInfo) {
        try {
            HashMap<String, String> httpHeaders = MapUtil.newHashMap(1);
            httpHeaders.put(COOKIE, cookie);
            JSONObject params = schedulerInfoToJson(schedulerInfo);
            requestAndResponseCheck(address + SCHEDULER_UPDATE_PATH, httpHeaders, params);
        } catch (Exception e) {
            log.warn("xxl-job调度任务更新异常,{}", e.getMessage());
            throw new XxlJobPlusException("调度任务更新异常:" + e.getMessage());
        }
    }

    @Override
    public void removeScheduler(String id) {
        removeScheduler(login(),xxlJobPlusProperties.getAdmin().getAddresses(),id);
    }

    /**
     * 删除调度任务
     *
     * @param cookie cookie
     * @param address address
     * @param id id
     * @return void
     * @author laoyu
     * @date 2023/2/17
     */
    @Override
    public void removeScheduler(String cookie, String address, String id) {
        try {
            HashMap<String, String> httpHeaders = MapUtil.newHashMap(1);
            httpHeaders.put(COOKIE, cookie);
            JSONObject params = JSONUtil.createObj();
            params.append("id",id);
            requestAndResponseCheck(address + SCHEDULER_REMOVE_PATH, httpHeaders, params);
        } catch (Exception e) {
            log.warn("xxl-job调度任务删除异常,{}", e.getMessage());
            throw new XxlJobPlusException("调度任务删除异常:" + e.getMessage());
        }
    }

    @Override
    public void startScheduler(String id) {
        startScheduler(login(),xxlJobPlusProperties.getAdmin().getAddresses(),id);
    }

    @Override
    public void startScheduler(String cookie, String address, String id) {
        try {
            HashMap<String, String> httpHeaders = MapUtil.newHashMap(1);
            httpHeaders.put(COOKIE, cookie);
            JSONObject params = JSONUtil.createObj();
            params.append("id",id);
            requestAndResponseCheck(address + SCHEDULER_START_PATH, httpHeaders, params);
        } catch (Exception e) {
            log.warn("xxl-job调度任务启动异常,{}", e.getMessage());
            throw new XxlJobPlusException("调度任务启动异常:" + e.getMessage());
        }
    }

    @Override
    public void stopScheduler(String id) {
        stopScheduler(login(),xxlJobPlusProperties.getAdmin().getAddresses(),id);
    }

    @Override
    public void stopScheduler(String cookie, String address, String id) {
        try {
            HashMap<String, String> httpHeaders = MapUtil.newHashMap(1);
            httpHeaders.put(COOKIE, cookie);
            JSONObject params = JSONUtil.createObj();
            params.append("id",id);
            requestAndResponseCheck(address + SCHEDULER_STOP_PATH, httpHeaders, params);
        } catch (Exception e) {
            log.warn("xxl-job调度任务停止异常,{}", e.getMessage());
            throw new XxlJobPlusException("调度任务停止异常:" + e.getMessage());
        }
    }

    @Override
    public void triggerScheduler(TriggerScheduler triggerScheduler) {
        triggerScheduler(login(),xxlJobPlusProperties.getAdmin().getAddresses(),triggerScheduler);
    }

    /**
     * 触发调度任务 
     *
     * @param cookie cookie
     * @param address address
     * @param triggerScheduler triggerScheduler 
     * @return void
     * @author laoyu
     * @date 2023/2/17
     */
    @Override
    public void triggerScheduler(String cookie, String address, TriggerScheduler triggerScheduler) {
        try {
            HashMap<String, String> httpHeaders = MapUtil.newHashMap(1);
            httpHeaders.put(COOKIE, cookie);
            JSONObject params = JSONUtil.parseObj(triggerScheduler);
            requestAndResponseCheck(address + SCHEDULER_TRIGGER_PATH, httpHeaders, params);
        } catch (Exception e) {
            log.warn("xxl-job触发调度任务异常,{}", e.getMessage());
            throw new XxlJobPlusException("触发调度任务异常:" + e.getMessage());
        }
    }


    /**
     * 调度任务模型转json参数 
     *
     * @param schedulerInfo schedulerInfo 
     * @return cn.hutool.json.JSONObject
     * @author laoyu
     * @date 2023/2/17
     */
    private static JSONObject schedulerInfoToJson(SchedulerInfo schedulerInfo) {
        JSONObject params = JSONUtil.createObj();
        params.append("jobGroup", schedulerInfo.getJobGroup());
        params.append("scheduleType", schedulerInfo.getScheduleType());
        params.append("scheduleConf", schedulerInfo.getScheduleConf());
        params.append("cronGen_display", schedulerInfo.getCronGenDisplay());
        params.append("schedule_conf_CRON", schedulerInfo.getScheduleConfCron());
        params.append("schedule_conf_FIX_RATE", schedulerInfo.getScheduleConfFixRate());
        params.append("schedule_conf_FIX_DELAY", schedulerInfo.getScheduleConfFixDelay());
        params.append("jobDesc", schedulerInfo.getJobDesc());
        params.append("author", schedulerInfo.getAuthor());
        params.append("alarmEmail", schedulerInfo.getAlarmEmail());
        params.append("executorRouteStrategy", schedulerInfo.getExecutorRouteStrategy());
        params.append("executorHandler", schedulerInfo.getExecutorHandler());
        params.append("executorParam", schedulerInfo.getExecutorParam());
        params.append("executorBlockStrategy", schedulerInfo.getExecutorBlockStrategy());
        params.append("executorTimeout", schedulerInfo.getExecutorTimeout());
        params.append("executorFailRetryCount", schedulerInfo.getExecutorFailRetryCount());
        params.append("misfireStrategy", schedulerInfo.getMisfireStrategy());
        params.append("glueType", schedulerInfo.getGlueType());
        params.append("glueSource", schedulerInfo.getGlueSource());
        params.append("glueRemark", schedulerInfo.getGlueRemark());
        return params;
    }


    /**
     * 调度任务列表请求
     *
     * @param url url
     * @param httpHeaders httpHeaders
     * @param params params
     * @param type type
     * @return java.util.List<T>
     * @author laoyu
     * @date 2023/2/16
     */
    public <T> List<T> list(String url, Map<String,String> httpHeaders, JSONObject params, Class<T> type) {
        HttpResponse response = HttpRequest.post(url).headerMap(httpHeaders, true).form(params).execute();
        JSONObject result = JSONUtil.parseObj(response.body());
        JSONArray executorList = result.getJSONArray("data");
        return JSONUtil.toList(executorList,type);
    }

    public XxlJobResult requestAndResponseCheck(String url, Map<String, String> httpHeaders, JSONObject params) {
        HttpResponse response = HttpRequest.post(url).headerMap(httpHeaders, true).form(params).execute();
        log.debug("register response:{}", response.body());
        XxlJobResult result = JSONUtil.toBean(response.body(), XxlJobResult.class);
        // 校验返回结果是否正确
        Assert.isTrue(result.isSuccess(),result.getMsg());
        return result;
    }

}
